package com.xxhg;

import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.util.Date;


public class MultivariateLinearRegressionExample1 {

    private static final String MODEL_FILE_PATH = "D:\\xibike\\回归测试\\model\\modelCoefficients451.ser";

    public static void main(String[] args) {
        Date now = new Date();
        // 如果模型文件不存在，则训练并保存模型
        if (!new File(MODEL_FILE_PATH).exists()) {
            trainAndSaveModel();
        }

        // 加载模型系数
        double[] coefficients = loadModelCoefficients();

        // 预测新数据点 回水 供水 室外温度 开度
        double[] newX =  {35.46, 39.79, 9, 100};
        // 归一化处理
        newX[3] = normalize(newX[3], 0, 100);
        double predictedY = predict(coefficients, newX);
        System.out.println("预测值: " + predictedY);
        System.out.println("耗时:" + (new Date().getTime() - now.getTime())+"ms");
    }

    private static void trainAndSaveModel() {
        // 读取 Excel 文件
        String excelFilePath = "D:\\xibike\\回归测试\\回归算法测试数据.xlsx";
        double[][] x = readExcelFile(excelFilePath);

        // 对阀门开度进行归一化处理
        for (int i = 1; i < x.length; i++) {
            x[i][3] = normalize(x[i][3], 0, 100);
        }

        // 读取目标变量（室温）
        double[] y = readTargetVariable(excelFilePath);

        // 创建多元线性回归对象
        OLSMultipleLinearRegression regression = new OLSMultipleLinearRegression();

        // 设置样本数据
        regression.newSampleData(y, x);

        // 获取回归系数
        double[] coefficients = regression.estimateRegressionParameters();

        // 保存模型系数到文件
        saveModelCoefficients(coefficients);
    }

    //保存模型
    private static void saveModelCoefficients(double[] coefficients) {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(MODEL_FILE_PATH))) {
            oos.writeObject(coefficients);
            System.out.println("模型系数已保存到文件：" + MODEL_FILE_PATH);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //读取模型
    private static double[] loadModelCoefficients() {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(MODEL_FILE_PATH))) {
            return (double[]) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static double predict(double[] coefficients, double[] newX) {
        // 添加截距项
        double[] newXWithIntercept = new double[newX.length + 1];
        newXWithIntercept[0] = 1.0;
        System.arraycopy(newX, 0, newXWithIntercept, 1, newX.length);

        double predictedY = 0.0;
        for (int i = 0; i < newXWithIntercept.length; i++) {
            predictedY += coefficients[i] * newXWithIntercept[i];
        }

        return predictedY;
    }
    // 读取 Excel 文件中的特征值
    private static double[][] readExcelFile(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);
            int rowCount = sheet.getLastRowNum()+1;
            //只读取前四列作为特征值
            int columnCount = 4;

            double[][] data = new double[rowCount][columnCount];

            for (int i = 1; i < rowCount; i++) {
                Row row = sheet.getRow(i);
                for (int j = 0; j < columnCount; j++) {
                    Cell cell = row.getCell(j);
                    if (cell != null) {
                        data[i][j] = cell.getNumericCellValue();
                    } else {
                        //处理空单元格
                        data[i][j] = 0.0;
                    }
                }
            }

            return data;

        } catch (IOException e) {
            e.printStackTrace();
            return new double[0][0];
        }
    }

    // 读取 Excel 文件中的目标变量（室温）
    private static double[] readTargetVariable(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);
            int rowCount = sheet.getLastRowNum() +1;
            //第四列作为目标变量
            int targetColumnIndex = 4;

            double[] target = new double[rowCount];

            for (int i = 1; i < rowCount; i++) {
                Row row = sheet.getRow(i);
                Cell cell = row.getCell(targetColumnIndex);
                if (cell != null) {
                    target[i] = cell.getNumericCellValue();
                } else {
                    //处理空单元格
                    target[i] = 0.0;
                }
            }

            return target;

        } catch (IOException e) {
            e.printStackTrace();
            return new double[0];
        }
    }

    //归一化
    private static double normalize(double value, double min, double max) {
        return (value - min) / (max - min);
    }

}